home *** CD-ROM | disk | FTP | other *** search
- /*
- * thread.c
- * Thread support.
- *
- * Copyright (c) 1996 Systems Architecture Research Centre,
- * City University, London, UK.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * Written by Tim Wilkinson <tim@sarc.city.ac.uk>, February 1996.
- */
-
- #include <assert.h>
- #include <string.h>
- #include "classMethod.h"
- #include "baseClasses.h"
- #include "object.h"
- #include "thread.h"
- #include "locks.h"
- #include "md.h"
-
- thread* threadQhead[MAX_THREAD_PRIO + 1];
- thread* threadQtail[MAX_THREAD_PRIO + 1];
- thread* finalman;
- thread* gcman;
- thread* currentThread;
- classes* ThreadClass;
- int blockInts;
- bool needReschedule;
-
- static int talive;
- static int tdaemon;
-
- extern classes* ClassClass;
-
- void reschedule(void);
- static void firstStartThread(void);
- static thread* startDaemon(void*);
- void finaliserMan(void);
- void gcMan(void);
-
- /*
- * Initialise threads.
- */
- void
- initThreads(void)
- {
- /* Get a handle on the thread class */
- ThreadClass = lookupClass(addString(THREADCLASS));
- assert(ThreadClass != 0);
-
- /* Allocate a thread to be the main thread */
- currentThread = (thread*)alloc_object(ThreadClass, true);
- assert(currentThread != 0);
-
- currentThread->name = 0;
- currentThread->priority = NORM_THREAD_PRIO;
- currentThread->next = 0;
- currentThread->PrivateInfo = THREAD_SUSPENDED;
- currentThread->eetop = (ctx*)malloc(sizeof(ctx));
- assert(currentThread->eetop != 0);
- THREADINFO(currentThread->eetop);
- currentThread->single_step = 0;
- currentThread->daemon = 0;
- currentThread->stillborn = 0;
- currentThread->target = 0;
- currentThread->group = (threadGroup*)execute_java_constructor(0, "java.lang.ThreadGroup", 0, "()V");
- assert(currentThread->group != 0);
-
- talive++;
-
- /* Add thread into runQ */
- resumeThread(currentThread);
-
- /* Start any daemons we need */
- finalman = startDaemon(&finaliserMan);
- gcman = startDaemon(&gcMan);
- }
-
- /*
- * Start a new thread running.
- */
- void
- startThread(thread* tid)
- {
- /* Allocate a stack context */
- assert(tid->eetop == 0);
- tid->eetop = (ctx*)malloc(sizeof(ctx));
- assert(tid->eetop != 0);
- tid->eetop->stackBase = (void*)malloc(THREADSTACKSIZE);
- assert(tid->eetop->stackBase != 0);
- tid->eetop->stackEnd = tid->eetop->stackBase + THREADSTACKSIZE;
- tid->PrivateInfo = THREAD_SUSPENDED;
-
- /* Construct the initial restore point. */
- THREADINIT(tid->eetop, &firstStartThread);
-
- talive++;
- if (tid->daemon) {
- tdaemon++;
- }
-
- /* Add thread into runQ */
- resumeThread(tid);
- }
-
- /*
- * All threads start here.
- */
- static
- void
- firstStartThread(void)
- {
- /* Every thread starts with the interrupts off */
- intsRestore();
-
- /* Find the run()V method and call it */
- do_execute_java_method(0, currentThread, "run", "()V", 0, 0);
- do_execute_java_method(0, currentThread, "exit", "()V", 0, 0);
- killThread(currentThread);
- }
-
- /*
- * Resume a thread running.
- */
- void
- resumeThread(thread* tid)
- {
- intsDisable();
-
- if (tid->PrivateInfo != THREAD_RUNNING) {
- tid->PrivateInfo = THREAD_RUNNING;
-
- /* Place thread on the end of its queue */
- if (threadQhead[tid->priority] == 0) {
- threadQhead[tid->priority] = tid;
- threadQtail[tid->priority] = tid;
- if (tid->priority > currentThread->priority) {
- needReschedule = true;
- }
- }
- else {
- threadQtail[tid->priority]->next = tid;
- threadQtail[tid->priority] = tid;
- }
- }
- intsRestore();
- }
-
- /*
- * Yield process to another thread of equal priority.
- */
- void
- yieldThread()
- {
- intsDisable();
-
- if (threadQhead[currentThread->priority] != threadQtail[currentThread->priority]) {
-
- /* Get the next thread and move me to the end */
- threadQhead[currentThread->priority] = currentThread->next;
- threadQtail[currentThread->priority]->next = currentThread;
- threadQtail[currentThread->priority] = currentThread;
- currentThread->next = 0;
- needReschedule = true;
- }
-
- intsRestore();
- }
-
- /*
- * Suspend a thread.
- */
- void
- suspendThread(thread* tid)
- {
- thread** ntid;
-
- intsDisable();
-
- if (tid->PrivateInfo != THREAD_SUSPENDED) {
- tid->PrivateInfo = THREAD_SUSPENDED;
-
- for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
- if (*ntid == tid) {
- *ntid = tid->next;
- if (tid == currentThread) {
- reschedule();
- }
- break;
- }
- }
- }
-
- intsRestore();
- }
-
- /*
- * Suspend a thread on a queue.
- */
- void
- suspendOnQThread(thread* tid, thread** queue)
- {
- thread** ntid;
-
- assert(blockInts == 1);
-
- if (tid->PrivateInfo != THREAD_SUSPENDED) {
- tid->PrivateInfo = THREAD_SUSPENDED;
-
- for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
- if (*ntid == tid) {
- *ntid = tid->next;
- /* Insert onto head of lock wait Q */
- tid->next = *queue;
- *queue = tid;
- if (tid == currentThread) {
- reschedule();
- }
- break;
- }
- }
- }
- }
-
- /*
- * Kill thread.
- */
- void
- killThread(thread* tid)
- {
- thread** ntid;
-
- intsDisable();
-
- if (tid->PrivateInfo != THREAD_DEAD) {
-
- /* Get thread of runq (if it needs it) */
- if (tid->PrivateInfo == THREAD_RUNNING) {
- for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
- if (*ntid == tid) {
- *ntid = tid->next;
- break;
- }
- }
- }
-
- tid->PrivateInfo = THREAD_DEAD;
- talive--;
- if (tid->daemon) {
- tdaemon--;
- }
-
- /* If we only have daemons left, then everyone is dead. */
- if (talive == tdaemon) {
- /* Am I suppose to close things down nicely ?? */
- exit(0);
- }
-
- /* Thread is garbage collected, don't worry about freeing it. */
-
- /* Run something else */
- needReschedule = true;
- }
- intsRestore();
- }
-
- /*
- * Change thread priority.
- */
- void
- setPriorityThread(thread* tid, int prio)
- {
- thread** ntid;
-
- if (tid->PrivateInfo == THREAD_SUSPENDED) {
- tid->priority = prio;
- return;
- }
-
- intsDisable();
-
- /* Remove from current thread list */
- for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
- if (*ntid == tid) {
- *ntid = tid->next;
- break;
- }
- }
-
- /* Insert onto a new one */
- tid->priority = prio;
- if (threadQhead[prio] == 0) {
- threadQhead[prio] = tid;
- threadQtail[prio] = tid;
- if (prio > currentThread->priority) {
- needReschedule = true;
- }
- }
- else {
- threadQtail[prio]->next = tid;
- threadQtail[prio] = tid;
- }
-
- intsRestore();
- }
-
- /*
- * Put a thread to sleep.
- */
- void
- sleepThread(long long time)
- {
- abort();
- }
-
- /*
- * Is this thread alive?
- */
- bool
- aliveThread(thread* tid)
- {
- return (tid->PrivateInfo != THREAD_DEAD ? true : false);
- }
-
- /*
- * How many stack frames have I invoked?
- */
- long
- framesThread(thread* tid)
- {
- long count;
- THREADFRAMES(tid, count);
- return (count);
- }
-
- /*
- * Reschedule the thread.
- * Called whenever a change in the running thread is required.
- */
- void
- reschedule(void)
- {
- int i;
- thread* lastThread;
- int b;
-
- /* Check events - we may release a high priority thread */
- checkEvents(false);
-
- for (;;) {
- for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--) {
- if (threadQhead[i] != 0) {
- if (threadQhead[i] != currentThread) {
- b = blockInts;
- lastThread = currentThread;
- currentThread = threadQhead[i];
- THREADSWITCH(currentThread->eetop, lastThread->eetop);
- blockInts = b;
- }
- /* Now we kill the schedule and turn ints
- back on */
- needReschedule = false;
- return;
- }
- }
- /* Nothing to run - wait for external event */
- checkEvents(true);
- }
- }
-
- /*
- * Start a daemon thread.
- */
- static
- thread*
- startDaemon(void* func)
- {
- thread* tid;
-
- tid = (thread*)alloc_object(ThreadClass, true);
- assert(tid != 0);
-
- tid->name = 0;
- tid->priority = MAX_THREAD_PRIO;
- tid->next = 0;
- tid->PrivateInfo = THREAD_SUSPENDED;
- tid->eetop = (ctx*)malloc(sizeof(ctx));
- assert(tid->eetop != 0);
- tid->eetop->stackBase = (void*)malloc(THREADSTACKSIZE);
- assert(tid->eetop->stackBase != 0);
- tid->eetop->stackEnd = tid->eetop->stackBase + THREADSTACKSIZE;
- tid->single_step = 0;
- tid->daemon = 1;
- tid->stillborn = 0;
- tid->target = 0;
- tid->group = 0;
-
- /* Construct the initial restore point. */
- THREADINIT(tid->eetop, func);
-
- talive++;
- tdaemon++;
-
- /* Add thread into runQ */
- resumeThread(tid);
-
- return (tid);
- }
-